/*Scott Rogowski and Yipeng Huang*/
/*smr2167 yh2315*/

#ifndef MIPSPIPE_H
#define MIPSPIPE_H

#include "string.h"

//incrementer (because we are using C and it doesn't like instantiations inside of for loops)
int i;

// the register memory
int reg_data[32];
int reg_valid[32];

// the data memory 2^16 (technically 2^32 but we will never get there because the initial 16 address is just sign extended to 32 so we don't need to worry about that and possibly crash the server with this ridiculous amount of memory.)
int mem_data[65536];
int mem_valid[65536];

//The expected value queues
//We know what should be coming back through the pipeline and when it should be coming back so we can implement queues to process this
int data_valid[5];
int data_rw[5];
int data_addr[5];
int data_value[5];
int inst_valid[5];
int inst_addr[5];

//These will write their data to our model register once on the 0 cycle
int reg_data_q[5];
int reg_addr_q[5];
int reg_write_q[5];

// input ports -- holds the input values driven on the previous cycle so they need to be cleared with clear_input_ports()
struct {
	int reset;
	int inst_i_valid;
	int inst_i;
	int data_i_valid;
	int data_i;
	} ports_i;

// output ports
struct {
	int inst_o_valid;
	int inst_o_addr;
	int data_o_valid;
	int data_o_rw;
	int data_o_addr;
	int data_o_value;
	} ports_o;

//Private methods
void update_queues();
void clear_input_ports();

//Compare verilog vs. C values
int process_instruction_request();
int process_data_request();

//Predict future based on which instruction sent
void add(int rs, int rt, int rd);
void addi(int rs, int rt, int immediate);
void lw(int rs, int rt, int immediate);
void sw(int rs, int rt, int immediate);
void beq(int rs, int rt, int immediate);
void jmp(int target);

//Set the pins
void set_data();
void set_instruction();
void set_reset();

#endif
